/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package gisgraph.components;

import edu.uci.ics.jung.algorithms.generators.random.BarabasiAlbertGenerator;
import edu.uci.ics.jung.graph.DirectedSparseGraph;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.util.EdgeType;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections15.Factory;
import org.jgrapht.VertexFactory;
import org.jgrapht.experimental.dag.DirectedAcyclicGraph;
import org.jgrapht.experimental.dag.DirectedAcyclicGraph.CycleFoundException;
import org.jgrapht.generate.RandomGraphGenerator;
import org.jgrapht.graph.DefaultEdge;

/**
 *
 * @author Slawek
 */
public class GISGraphGenerator {

    public DirectedSparseGraph<GISVertex, GISEdge> create(int num_vertices, GISEdgeFactory eFactory, GISVertexFactory vFactory) {
        
        GraphFactory gFactory = new GraphFactory();
        
        Map<GISEdge, Number> map = new Hashtable<GISEdge, Number>();
        Set<GISVertex> verticeSet = new HashSet<GISVertex>();
        
        int seed = (int)(Math.random() * 10000);
        BarabasiAlbertGenerator<GISVertex, GISEdge> bag = 
            new BarabasiAlbertGenerator<GISVertex, GISEdge>(
                gFactory, 
                vFactory, 
                eFactory,
                4, 
                3,
                seed,
                verticeSet);

        bag.evolveGraph(num_vertices - 4);
        Graph<GISVertex, GISEdge> ug = bag.create();

        // create a SparseMultigraph version of g
        DirectedSparseGraph<GISVertex, GISEdge> g = new DirectedSparseGraph<GISVertex, GISEdge>();
        
        DirectedAcyclicGraph<GISVertex, DefaultEdge> dag = 
                new DirectedAcyclicGraph<GISVertex, DefaultEdge>(DefaultEdge.class);
        
        for(GISVertex v : ug.getVertices()) {
                g.addVertex(v);
                dag.addVertex(v);
        }
        
        // randomly replace some of the edges by directed edges to 
        // get a mixed-mode graph, add random weights
        
        for(GISEdge e : ug.getEdges()) {
            GISVertex v1 = ug.getEndpoints(e).getFirst();
            GISVertex v2 = ug.getEndpoints(e).getSecond();

            GISEdge me = eFactory.create();
            try {
                dag.addDagEdge(v2, v1);
                g.addEdge(me, v1, v2, EdgeType.DIRECTED);
            }
            catch (CycleFoundException ex) {}
        }
        
        return g;
    }
    
    public DirectedAcyclicGraph<GISVertex, JGraphEdge> create2(int nrVertices, int nrEdges, GISEdgeFactory eFactory, GISVertexFactory vFactory)
    {
        RandomGraphGenerator<GISVertex, JGraphEdge> generator = 
                new RandomGraphGenerator<GISVertex, JGraphEdge>(nrVertices, nrEdges);
        
        DirectedAcyclicGraph<GISVertex, JGraphEdge> g = 
            new DirectedAcyclicGraph<GISVertex, JGraphEdge>(JGraphEdge.class);
        
        JGraphVertexFactory factory = new JGraphVertexFactory(vFactory);

        generator.generateGraph(g, factory, null);
        
        // TODO: tutaj trzeba zaciągnąć krawędzie i wygenerować wagi
        Set<JGraphEdge> eSet =  g.edgeSet();
        
        for (JGraphEdge e : eSet)
        {
            e.setWeight(eFactory.create().getWeight());
        }

        return g;
    }
    
    private class GraphFactory implements Factory<Graph<GISVertex, GISEdge>> {
        public Graph<GISVertex, GISEdge> create() {
            return new DirectedSparseGraph<GISVertex, GISEdge>();
        }
    }
    
    private class JGraphVertexFactory implements VertexFactory<GISVertex>
    {
        private GISVertexFactory vFactory;

        public JGraphVertexFactory(GISVertexFactory vFactory)
        {
            this.vFactory = vFactory;
        }
        
        public GISVertex createVertex() {
            return vFactory.create();
        }
    }
}
